package com.weitu.base.aop;


import com.weitu.base.annotaion.SystemLog;
import com.weitu.base.controller.BaseController;
import com.weitu.permission.log.entity.HandleLog;
import com.weitu.permission.log.service.LogService;
import com.weitu.permission.user.entity.User;
import com.weitu.util.DateTimeUtil;
import com.weitu.util.IDGenerator;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 切点类
 *
 * @author zhangqingxi
 */
@Aspect
@Component

public class SystemLogAop {
    // 本地异常日志记录对象
    private static final Logger logger = LoggerFactory.getLogger(SystemLogAop.class);

    private final LogService logService;

    @Autowired
    public SystemLogAop(LogService logService) {
        this.logService = logService;
    }

    // Controller层切点
    @Pointcut("@annotation(com.weitu.base.annotaion.SystemLog)")
    public void controllerAspect() {
    }

    /**
     * 操作异常记录
     *
     * @param joinPoint joinPoint
     * @param throwable throwable
     */
    @AfterThrowing(pointcut = "controllerAspect()", throwing = "throwable")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable throwable) {

        HandleLog handleLog = new HandleLog();

        Map<String, Object> map = null;

        String dateTime = DateTimeUtil.formatterDateTime();
        String uuid = IDGenerator.getId();

        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();

        User loginUser;
        String userId;
        //获得session对象
        Session session = SecurityUtils.getSubject().getSession();
        try {
            map = getControllerMethodDescription(joinPoint);
            loginUser = (User) session.getAttribute("loginUser");

            if (null != loginUser) {
                userId = loginUser.getId();
            } else {
                userId = "无法获取登录用户信息！";
            }

        } catch (Exception e) {
            userId = "无法获取登录用户信息！";
        }

        handleLog.setId(uuid);//id
        handleLog.setHandleTime(dateTime);//操作时间
        handleLog.setHandleIp(session.getHost());//操作IP
        handleLog.setHandleUserId(userId);//操作用户Id

        handleLog.setModuleCode("<font color=\"red\">" + className + "</font>");//操作模块的标识
        handleLog.setModuleName("<font color=\"red\">" + map.get("module") + "</font>");//操作模块的名称

        handleLog.setFunctionCode("<font color=\"red\">" + methodName + "</font>");//操作方法的标识
        handleLog.setFunctionName("<font color=\"red\">" + map.get("methods") + "</font>");//操作方法的名称

        handleLog.setHandleContent("<font color=\"red\">" + throwable + "</font>");//操作内容

        handleLog.setRemarks("<font color=\"red\">执行方法异常!</font>");//操作内容


        //调用插入日志的方法
        logService.insertHandleLog(handleLog);
    }

    /**
     * 前置通知 用于拦截Controller层记录用户的操作
     *
     * @param point 切点
     * @return
     */
    @Around("controllerAspect()")
    public Object doController(ProceedingJoinPoint point) {

        HandleLog handleLog = new HandleLog();

        String dateTime = DateTimeUtil.formatterDateTime();
        String uuid = IDGenerator.getId();

        Object result;
        // 执行方法名
        String methodName = point.getSignature().getName();
        String className = point.getTarget().getClass().getSimpleName();

        Map<String, Object> map;
        User loginUser;
        String userId;
        Long start;
        Long end;
        Long time;
        //获得session对象
        Session session = SecurityUtils.getSubject().getSession();

        // 当前用户
        try {
            map = getControllerMethodDescription(point);

            loginUser = (User) session.getAttribute("loginUser");

            if (null != loginUser) {
                userId = loginUser.getId();
            } else {
                userId = "无法获取登录用户信息！";

            }
            // 执行方法所消耗的时间
            start = System.currentTimeMillis();
            result = point.proceed();
            end = System.currentTimeMillis();
            time = end - start;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        try {

            String field = map.get("field").toString();
            //获得参数删除添加操作中的Id进行记录
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String id = request.getParameter(field) == null ? "" : request.getParameter(field);

            handleLog.setId(uuid);//id
            handleLog.setHandleTime(dateTime);//操作时间
            handleLog.setHandleIp(session.getHost());//操作IP
            handleLog.setHandleUserId(userId);//操作用户Id

            handleLog.setModuleCode(className);//操作模块的标识
            handleLog.setModuleName(map.get("module").toString());//操作模块的名称

            handleLog.setFunctionCode(methodName);//操作方法的标识
            handleLog.setFunctionName(map.get("methods").toString());//操作方法的名称

            handleLog.setHandleContent(id);//操作内容
            handleLog.setRemarks(map.get("description").toString());//操作结果

            //插入数据库
            logService.insertHandleLog(handleLog);
            // *========控制台输出=========*//
            System.out.println("=====通知开始=====");
            System.out.println("请求方法:" + className + "." + methodName + "()");
            System.out.println("方法描述:" + map);
            System.out.println("方法执行时间:" + time);
            System.out.println("=====通知结束=====");

        } catch (Exception e) {
            // 记录本地异常日志
            logger.error("====通知异常====");
            logger.error("异常信息:{}", e.getMessage());
        }
        return result;
    }

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception e
     */
    private Map<String, Object> getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    SystemLog systemLog = method.getAnnotation(SystemLog.class);
                    map.put("module", systemLog.module());
                    map.put("methods", systemLog.methods());
                    String description = systemLog.description();
                    String field = systemLog.field();
                    if (StringUtils.isEmpty(description)) {
                        description = "执行成功!";
                    }
                    if (StringUtils.isEmpty(description)) {
                        field = "id";
                    }
                    map.put("description", description);
                    map.put("field", field);
                    break;
                }
            }
        }
        return map;
    }


}
